﻿// <copyright file="GlobalImporter.cs" company="Gravity Age Studios">
// Code released under the MIT license (see License.txt).
// </copyright>
// <author>Vicente Cartas Espinel</author>
// <email>vicente.cartas@gmail.com</email>
namespace LightSwitchApplication.Import
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using Ionic.Zip;

    internal class GlobalImporter
    {
        private readonly string AlignmentsFileKey = "Alignments";
        private readonly string BloodAbilitiesFileKey = "BloodAbilities";
        private readonly string BloodlineDerivationsFileKey = "BloodlineDerivations";
        private readonly string BloodlineStrenghtsFileKey = "BloodlineStrengths";
        private readonly string ClassesFileKey = "Classes";
        private readonly string DeitiesFileKey = "Deities";
        private readonly string RacesFileKey = "Races";
        private readonly string RealmSpellsFileKey = "RealmSpells";
        private readonly string SkillsFileKey = "Skills";

        private readonly string ClassImagesDirectoryKey = "ClassesImages";
        private readonly string DeitiesImagesDirectoryKey = "DeitiesImages";

        private readonly string BaseActionsFileKey = "BaseActions";
        private readonly string BaseLandUnitsFileKey = "BaseLandUnits";
        private readonly string BaseSeaUnitsFileKey = "BaseSeaUnits";
        private readonly string BaseProvincesFileKey = "BaseProvinces";
        private readonly string NeighboursFileKey = "Neighbours";
        private readonly string TerrainsFileKey = "Terrains";

        private readonly string ArmiesFileKey = "Armies";
        private readonly string LandUnitsFileKey = "LandUnits";
        private readonly string SeaUnitsFileKey = "SeaUnits";
        private readonly string CharactersFileKey = "Characters";
        private readonly string DomainsFileKey = "Domains";
        private readonly string DomainProvincesFileKey = "DomainProvinces";
        private readonly string DomainTurnsFileKey = "DomainTurns";
        private readonly string DomainActionsFileKey = "DomainActions";
        private readonly string GameInformationFileKey = "GameInformation";
        private readonly string PlayersFileKey = "Players";

        private readonly string CharacterSheetsDirectoryKey = "CharactersSheets";
        private readonly string DomainImagesDirectoryKey = "DomainsImages";

        private DataWorkspace workspace;

        public GlobalImporter(DataWorkspace workspace)
        {
            this.workspace = workspace;
        }

        public void ImportData(Stream stream)
        {
            ZipFile file = ZipFile.Read(stream);
            var indexes = this.CreateIndex(file.Entries.FirstOrDefault(e => e.FileName.Equals("index.txt", StringComparison.InvariantCultureIgnoreCase)));
            this.ImportData(indexes, file.Entries);

            //using (ZipFile file = ZipFile.Read(stream))
            //{
            //    var indexes = this.CreateIndex(file.Entries.FirstOrDefault(e => e.FileName.Equals("index.txt", StringComparison.InvariantCultureIgnoreCase)));
            //    this.ImportData(indexes, file.Entries);
            //}
        }

        private Dictionary<string, List<string>> CreateIndex(ZipEntry entry)
        {
            Dictionary<string, List<string>> contentIndexes = new Dictionary<string, List<string>>();

            contentIndexes.Add(AlignmentsFileKey, new List<string>());
            contentIndexes.Add(BloodAbilitiesFileKey, new List<string>());
            contentIndexes.Add(BloodlineDerivationsFileKey, new List<string>());
            contentIndexes.Add(BloodlineStrenghtsFileKey, new List<string>());
            contentIndexes.Add(ClassesFileKey, new List<string>());
            contentIndexes.Add(DeitiesFileKey, new List<string>());
            contentIndexes.Add(RacesFileKey, new List<string>());
            contentIndexes.Add(RealmSpellsFileKey, new List<string>());
            contentIndexes.Add(SkillsFileKey, new List<string>());
            contentIndexes.Add(ClassImagesDirectoryKey, new List<string>());
            contentIndexes.Add(DeitiesImagesDirectoryKey, new List<string>());
            contentIndexes.Add(BaseActionsFileKey, new List<string>());
            contentIndexes.Add(BaseLandUnitsFileKey, new List<string>());
            contentIndexes.Add(BaseSeaUnitsFileKey, new List<string>());
            contentIndexes.Add(BaseProvincesFileKey, new List<string>());
            contentIndexes.Add(NeighboursFileKey, new List<string>());
            contentIndexes.Add(TerrainsFileKey, new List<string>());
            contentIndexes.Add(ArmiesFileKey, new List<string>());
            contentIndexes.Add(LandUnitsFileKey, new List<string>());
            contentIndexes.Add(SeaUnitsFileKey, new List<string>());
            contentIndexes.Add(CharactersFileKey, new List<string>());
            contentIndexes.Add(DomainsFileKey, new List<string>());
            contentIndexes.Add(DomainProvincesFileKey, new List<string>());
            contentIndexes.Add(DomainTurnsFileKey, new List<string>());
            contentIndexes.Add(DomainActionsFileKey, new List<string>());
            contentIndexes.Add(GameInformationFileKey, new List<string>());
            contentIndexes.Add(PlayersFileKey, new List<string>());
            contentIndexes.Add(CharacterSheetsDirectoryKey, new List<string>());
            contentIndexes.Add(DomainImagesDirectoryKey, new List<string>());

            using (MemoryStream memory = new MemoryStream())
            {
                entry.Extract(memory);
                memory.Seek(0, SeekOrigin.Begin);
                using (StreamReader reader = new StreamReader(memory))
                {
                    string[] indexes = reader.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (string index in indexes)
                    {
                        string[] keyValue = index.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
                        if (keyValue != null || keyValue.Length == 2)
                        {
                            if (contentIndexes.ContainsKey(keyValue[0].Trim()))
                            {
                                contentIndexes[keyValue[0].Trim()].AddRange(keyValue[1].Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries));
                            }
                        }
                    }
                }
            }

            return contentIndexes;
        }

        private void ImportData(Dictionary<string, List<string>> indexes, IEnumerable<ZipEntry> files)
        {
            try
            {
                this.workspace.Details.Dispatcher.BeginInvoke(() =>
                {
                    // The following data does not depend on anything else
                    Import(indexes[AlignmentsFileKey], files, new AlignmentImporter(this.workspace).ImportData);
                    Import(indexes[BloodlineDerivationsFileKey], files, new BloodlineDerivationImporter(this.workspace).ImportData);
                    Import(indexes[BloodlineStrenghtsFileKey], files, new BloodlineStrengthImporter(this.workspace).ImportData);
                    Import(indexes[ClassesFileKey], files, new ClassImporter(this.workspace).ImportData);
                    Import(indexes[RacesFileKey], files, new RaceImporter(this.workspace).ImportData);
                    Import(indexes[SkillsFileKey], files, new SkillImporter(this.workspace).ImportData);
                    Import(indexes[BaseActionsFileKey], files, new BaseActionImporter(this.workspace).ImportData);
                    Import(indexes[TerrainsFileKey], files, new TerrainImporter(this.workspace).ImportData);
                    Import(indexes[GameInformationFileKey], files, new GameInformationImporter(this.workspace).ImportData);
                    Import(indexes[PlayersFileKey], files, new PlayerImporter(this.workspace).ImportData);

                    // Blood abilities depend on BloodlineStrength and BloodlineDerivation.
                    // Deities depend on Alignment. BaseProvinces depend on Terrain.
                    Import(indexes[BloodAbilitiesFileKey], files, new BloodAbilityImporter(this.workspace).ImportData);
                    Import(indexes[DeitiesFileKey], files, new DeityImporter(this.workspace).ImportData);
                    Import(indexes[BaseProvincesFileKey], files, new BaseProvinceImporter(this.workspace).ImportData);
                    this.GenerateDomainProvinces();

                    // Neighbours depend on BaseProvinces. Characters depend on a lot of things.
                    Import(indexes[NeighboursFileKey], files, new NeighbourImporter(this.workspace).ImportData);
                    Import(indexes[CharactersFileKey], files, new CharacterImporter(this.workspace).ImportData);

                    // RealmSpells depend on Characters. Domains depend on Characters.
                    Import(indexes[RealmSpellsFileKey], files, new RealmSpellImporter(this.workspace).ImportData);
                    Import(indexes[DomainsFileKey], files, new DomainImporter(this.workspace).ImportData);

                    // BaseUnits depend on Domains. DomainProvinces depend on Domains and BaseProvinces.
                    // DomainTurns depend on Domains. Players depend on Domains
                    Import(indexes[BaseLandUnitsFileKey], files, new BaseLandUnitImporter(this.workspace).ImportData);
                    Import(indexes[BaseSeaUnitsFileKey], files, new BaseSeaUnitImporter(this.workspace).ImportData);
                    Import(indexes[DomainProvincesFileKey], files, new DomainProvinceImporter(this.workspace).ImportData);
                    Import(indexes[DomainTurnsFileKey], files, new DomainTurnImporter(this.workspace).ImportData);

                    // Armies depend on DomainProvinces. DomainActions depend on DomainTurns.
                    Import(indexes[ArmiesFileKey], files, new ArmyImporter(this.workspace).ImportData);
                    Import(indexes[DomainActionsFileKey], files, new DomainActionImporter(this.workspace).ImportData);
                    this.workspace.ApplicationData.SaveChanges();

                    // SeaUnits depend on Armies.
                    Import(indexes[SeaUnitsFileKey], files, new SeaUnitImporter(this.workspace).ImportData);

                    // LandUnits depend on SeaUnits.
                    Import(indexes[LandUnitsFileKey], files, new LandUnitImporter(this.workspace).ImportData);
                });
            }
            catch (Exception e)
            {
                throw;
            }
        }

        private void Import(List<string> fileNames, IEnumerable<ZipEntry> files, Action<Stream, bool> import)
        {
            foreach (string fileName in fileNames)
            {
                ZipEntry file = files.FirstOrDefault(e => e.FileName.Equals(fileName, StringComparison.InvariantCultureIgnoreCase));
                if (file == null)
                {
                    return;
                }

                using (MemoryStream memory = new MemoryStream())
                {
                    file.Extract(memory);
                    memory.Seek(0, SeekOrigin.Begin);
                    import(memory, false);
                }

                this.workspace.ApplicationData.SaveChanges();
            }
        }

        private void GenerateDomainProvinces()
        {
            foreach (var baseProvince in this.workspace.ApplicationData.BaseProvinces.GetQuery().Execute())
            {
                if (baseProvince.DomainProvince == null)
                {
                    var domainProvince = this.workspace.ApplicationData.DomainProvinces.AddNew();

                    domainProvince.Visibility = baseProvince.Visibility;
                    domainProvince.BaseProvince = baseProvince;
                    domainProvince.PopulationLevel = 0;
                    domainProvince.FortificationLevel = 0;
                    domainProvince.Loyalty = 0;
                }
            }

            this.workspace.ApplicationData.SaveChanges();
        }
    }
}
